var express = require("express");
var router = express.Router();
const fs = require("fs/promises");
const path = require("path");
const ffmpeg = require("fluent-ffmpeg");
const logger = require("winston");
const uuid = require("uuid");
const { Mutex } = require("async-mutex");
const { spawn } = require("child_process");

const now = new Date();
const year = now.getFullYear(); // 获取年份，例如 2025
const month = String(now.getMonth() + 1).padStart(2, "0"); // 获取月份，从 0 开始，需要加 1，并补零
const day = String(now.getDate()).padStart(2, "0"); // 获取日期，并补零

// 初始化线程池
const ThreadPool = require("../utils/thread-pool");
const pool = new ThreadPool(4, "../utils/hls-worker.js");

// 配置日志
logger.configure({
  level: "debug",
  transports: [
    new logger.transports.Console({
      level: "info",
      format: logger.format.combine(
        logger.format.timestamp(),
        logger.format.printf(
          (info) => `${info.timestamp} - ${info.level} - ${info.message}`
        )
      ),
    }),
    new logger.transports.File({
      level: "debug",
      filename: `express_${year}${month}${day}.log`,
      format: logger.format.combine(
        logger.format.timestamp(),
        logger.format.printf(
          (info) => `${info.timestamp} - ${info.level} - ${info.message}`
        )
      ),
      maxsize: 10485760, // 10MB
      maxFiles: 5,
      tailable: true,
    }),
  ],
});

const VIDEO_DIR = path.resolve(__dirname, "../public/videos");
// const VIDEO_DIR = path.resolve("E:\\My Documents\\My Videos");
const HLS_DIR = path.resolve(__dirname, "../public/hls");
const BASE_URL = "http://localhost:8888";
const HLS_URL = BASE_URL + "/hls";
const mutex = new Mutex();
const activeProcesses = new Map();

// 获取视频信息
async function getVideoInfo(videoPath) {
  return new Promise((resolve, reject) => {
    ffmpeg.ffprobe(videoPath, (err, metadata) => {
      if (err) {
        logger.error(`ffprobe 执行失败，错误信息: ${err.message}`);
        reject(null);
        return;
      }
      const videoStream = metadata.streams.find(
        (s) => s.codec_type === "video"
      );
      if (!videoStream) {
        logger.error(`警告：未找到视频流，视频路径: ${videoPath}`);
        reject(null);
        return;
      }
      const filename = path.basename(videoPath);
      const filepath = path.resolve(videoPath);
      const url = `/video/${encodeURIComponent(filename)}`;
      resolve({
        id: "",
        filename,
        filepath,
        url,
        width: videoStream.width,
        height: videoStream.height,
        codec: videoStream.codec_name,
        duration_sec: parseFloat(metadata.format.duration),
      });
    });
  });
}

// 加载视频信息
async function loadVideoInfo() {
  const release = await mutex.acquire();
  try {
    const dataFile = "video_details.json";
    try {
      const videoInfoList = JSON.parse(await fs.readFile(dataFile, "utf-8"));
      logger.debug(`成功加载 ${videoInfoList.length} 条视频信息数据`);
      return videoInfoList;
    } catch (err) {
      if (err.code === "ENOENT") {
        logger.warn(`文件不存在，返回空数组: ${dataFile}`);
      } else {
        logger.error(`读取文件时出错: ${err.message}`);
      }
      return [];
    }
  } catch (e) {
    logger.error(`加载视频信息数据失败: ${e.message}`);
  } finally {
    release();
  }
}

// 保存视频信息
async function saveVideoInfo(videoInfoList) {
  const release = await mutex.acquire();
  try {
    const dataFile = "video_details.json";
    if (videoInfoList && videoInfoList.length > 0) {
      try {
        await fs.writeFile(
          dataFile,
          JSON.stringify(videoInfoList, null, 2),
          "utf-8"
        );
        logger.debug(`视频信息已保存为 ${dataFile}`);
      } catch (e) {
        logger.error(`视频信息保存失败: ${e.message}`);
      }
    }
  } finally {
    release();
  }
}

// 生成视频列表
async function getVideoList() {
  let videoInfoList = await loadVideoInfo();
  if (videoInfoList.length > 0) {
    return videoInfoList;
  }
  videoInfoList = [];
  const files = await fs.readdir(VIDEO_DIR);
  const promises = files.map(async (filename) => {
    const videoExtensions = [".mp4", ".avi", ".mov", ".mkv", ".wmv", ".rmvb"];
    // 将文件名转换为小写，并检查是否以视频扩展名结尾
    if (videoExtensions.some((ext) => filename.toLowerCase().endsWith(ext))) {
      const videoPath = path.resolve(VIDEO_DIR, filename);
      const info = await getVideoInfo(videoPath);
      if (info) {
        info.id = uuid.v4();
        if (info.codec && info.codec.toLowerCase().endsWith("h264")) {
          info.url = BASE_URL + `/videos/${info.filename}`;
        } else {
          info.url = HLS_URL + `/${info.id}/playlist.m3u8`;
        }
        videoInfoList.push(info);
      }
    }
  });
  await Promise.all(promises);
  await saveVideoInfo(videoInfoList);
  return videoInfoList;
}

// 检查路径是否存在
async function checkDirectoryExists(dirPath) {
  try {
    await fs.access(dirPath);
    logger.debug(`目录存在：${dirPath}`);
    return true;
  } catch (err) {
    if (err.code === "ENOENT") {
      logger.debug(`目录不存在：${dirPath}`);
    } else {
      logger.debug(`访问目录出错：${err.message}`);
    }
    return false;
  }
}

/* GET home page. */
router.get("/", function (req, res, next) {
  res.render("index", { title: "Marin Player" });
});

// 获取视频列表（JSON接口）
router.get("/video/list", async (req, res, next) => {
  try {
    const videos = await getVideoList();
    res.json(videos);
  } catch (err) {
    next(err);
  }
});

// 视频流接口
router.get("/video/:videoId", async (req, res, next) => {
  const videoId = req.params.videoId;
  if (!videoId) {
    res.status(400).send("参数错误");
    return;
  }

  try {
    // 1. 获取视频信息（原有逻辑保留）
    const videoInfoList = await getVideoList();
    const videoInfo = videoInfoList.find((v) => v.id === videoId);
    if (!videoInfo) {
      res.status(404).send("videoInfo not found");
      return;
    }

    if (videoInfo.url && !videoInfo.url.toLowerCase().endsWith(".m3u8")) {
      res.status(200).send(videoInfo.url);
      return;
    }

    // 2. 创建 HLS 唯一目录（原有逻辑保留）
    const uniqueDir = path.join(HLS_DIR, videoInfo.id);
    await fs.mkdir(uniqueDir, { recursive: true });

    // 3. 定义关键路径
    const m3u8Path = path.join(uniqueDir, "playlist.m3u8");

    // 6. 处理已有 m3u8 文件（新增文件处理）
    try {
      const m3u8Content = await fs.readFile(m3u8Path, "utf-8");
      if (m3u8Content.includes("#EXT-X-ENDLIST")) {
        res.status(200).send(videoInfo.url);
        return;
      }
      // 移除已有结束标记
      // const modifiedContent = m3u8Content.replace(/#EXT-X-ENDLIST[\r\n]*/g, "");
      // await fs.writeFile(m3u8Path, modifiedContent);
    } catch (err) {
      logger.debug("未找到已有 m3u8 文件");
    }

    // 提交转码任务到线程池
    pool
      .execute({
        videoInfo,
        outputDir: HLS_DIR,
      })
      .then((result) => {
        logger.info(`转码完成: ${result.videoId}`);
      })
      .catch((err) => {
        logger.error(`转码失败: ${err.message}`);
      });

    // 5. 监听 m3u8 文件生成（新增核心逻辑）
    const checkM3U8 = async () => {
      try {
        await fs.access(m3u8Path);
        const content = await fs.readFile(m3u8Path, "utf-8");
        if (content.includes(".ts")) {
          return true; // 检测到有效 m3u8
        }
      } catch (err) {
        return false;
      }
    };

    // 6. 轮询检测（每 100ms 检查一次，最长等待 10s）
    const startCheck = Date.now();
    const poll = async () => {
      if (Date.now() - startCheck > 10000) {
        res.status(500).send("m3u8 生成超时");
      }
      if (await checkM3U8()) {
        // 立即返回播放地址
        res.status(200).json({
          url: `/hls/${videoId}/playlist.m3u8`,
        });
      } else {
        setTimeout(poll, 100);
      }
    };

    poll().catch((err) => {
      res.status(500).send("无法生成流");
    });
  } catch (err) {
    next(err);
  }
});

module.exports = router;
